package com.xyazm.order.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xyazm.common.enums.OrderStatusEnum;
import com.xyazm.common.exception.BaseBusinessErrorCodeEnum;
import com.xyazm.common.logger.LoggerFormat;
import com.xyazm.common.page.PagingInfo;
import com.xyazm.common.utils.ParamCheckUtil;
import com.xyazm.order.dao.*;
import com.xyazm.order.domain.builder.OrderDetailBuilder;
import com.xyazm.order.domain.dto.OrderDetailDTO;
import com.xyazm.order.domain.dto.OrderLackItemDTO;
import com.xyazm.order.domain.dto.OrderListDTO;
import com.xyazm.order.domain.dto.QueryOrderListDTO;
import com.xyazm.order.domain.entity.*;
import com.xyazm.order.domain.param.QueryOrderDetailParam;
import com.xyazm.order.domain.param.QueryOrderParam;
import com.xyazm.order.enums.BusinessIdentifierEnum;
import com.xyazm.common.enums.OrderTypeEnum;
import com.xyazm.order.exception.OrderErrorCodeEnum;
import com.xyazm.order.service.IAfterSaleQueryService;
import com.xyazm.order.service.IOrderLackService;
import com.xyazm.order.service.IOrderQueryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;

@Slf4j
@Service
public class OrderQueryServiceImpl implements IOrderQueryService {

    @Autowired
    private OrderInfoDAO orderInfoDAO;

    @Autowired
    private OrderItemDAO orderItemDAO;

    @Autowired
    private OrderDeliveryDetailDAO orderDeliveryDetailDAO;

    @Autowired
    private OrderPaymentDetailDAO orderPaymentDetailDAO;

    @Autowired
    private OrderAmountDAO orderAmountDAO;

    @Autowired
    private OrderAmountDetailDAO orderAmountDetailDAO;

    @Autowired
    private OrderOperateLogDAO orderOperateLogDAO;

    @Autowired
    private OrderSnapshotDAO orderSnapshotDAO;

    @Autowired
    private IAfterSaleQueryService afterSaleQueryService;

    @Autowired
    private IOrderLackService orderLackService;


    @Override
    public PagingInfo<OrderListDTO> listOrders(QueryOrderParam param) {
        // 校验查询参数
        checkQueryOrderParam(param);
        // 第一阶段采用很low的连表查询，连接5张表，即使加索引，只要数据量稍微大一点查询性能就很低了
        // 第二阶段会接入es，优化这块的查询性能

        // 组装业务查询规则
        QueryOrderListDTO queryDTO = QueryOrderListDTO.Builder.builder()
                .copy(param)
                //不展示无效订单
                .removeInValidStatus()
                .setPage(param)
                .build();

        log.info(LoggerFormat.build()
                .remark("listOrders->request")
                .data("request", queryDTO)
                .finish());

        // 查询订单列表信息
        Page<OrderListDTO> page = orderInfoDAO.listByPage(queryDTO);

        return PagingInfo.toResponse(page.getRecords(), page.getTotal(),
                (int)page.getCurrent(), (int) page.getSize());
    }

    @Override
    public OrderDetailDTO orderDetail(QueryOrderDetailParam param) {
        String orderId = param.getOrderId();
        ParamCheckUtil.checkStringNonEmpty(orderId, OrderErrorCodeEnum.ORDER_ID_IS_NULL);
        //1、查询订单
        OrderInfoDO orderInfoDO = orderInfoDAO.getByOrderId(orderId);
        if(orderInfoDO == null) {
            return null;
        }
        //2、查询订单条目
        List<OrderItemDO> orderItems = orderItemDAO.listByOrderId(orderId);
        //3、查询订单费用明细
        List<OrderAmountDetailDO> orderAmountDetails = orderAmountDetailDAO.listByOrderId(orderId);
        //4、查询订单配送信息
        OrderDeliveryDetailDO orderAmountDetail = orderDeliveryDetailDAO.getByOrderId(orderId);
        //5、查询订单支付明细
        List<OrderPaymentDetailDO> orderPaymentDetails = orderPaymentDetailDAO.listByOrderId(orderId);
        //6、查询订单费用类型
        List<OrderAmountDO> orderAmounts = orderAmountDAO.listByOrderId(orderId);
        //7、查询订单操作日志
        List<OrderOperateLogDO> orderOperateLogs = orderOperateLogDAO.listByOrderId(orderId);
        //8、查询订单快照
        List<OrderSnapshotDO> orderSnapshots = orderSnapshotDAO.listByOrderId(orderId);
        //9、查询缺品退款信息
        List<OrderLackItemDTO> lackItems = null;
        if(orderLackService.isOrderLacked(orderInfoDO)) {
            lackItems = afterSaleQueryService.getOrderLackItemInfo(orderId);
        }
        //10、构造返参
        return new OrderDetailBuilder()
                .orderInfo(orderInfoDO)
                .orderItems(orderItems)
                .orderAmountDetails(orderAmountDetails)
                .orderDeliveryDetail(orderAmountDetail)
                .orderPaymentDetails(orderPaymentDetails)
                .orderAmounts(orderAmounts)
                .orderOperateLogs(orderOperateLogs)
                .orderSnapshots(orderSnapshots)
                .lackItems(lackItems)
                .build();
    }



    /**
     * 校验查询订单列表入参
     * @author xuyou
     * @date: 2022/6/24 11:14
     * @param: param
     */
    private void checkQueryOrderParam(QueryOrderParam param) {
        // 校验 业务线 传值是否正确
        ParamCheckUtil.checkObjectNonNull(param.getBusinessIdentifier(),OrderErrorCodeEnum.BUSINESS_IDENTIFIER_IS_NULL);
        ParamCheckUtil.checkIntAllowableValues(
                param.getBusinessIdentifier(),
                BusinessIdentifierEnum.allowableValues(),
                BaseBusinessErrorCodeEnum.ENUM_PARAM_MUST_BE_IN_ALLOWABLE_VALUE,
                "businessIdentifier",
                BusinessIdentifierEnum.allowableValues());

        // 校验 订单类型 传值是否正确
        ParamCheckUtil.checkIntSetAllowableValues(
                param.getOrderTypes(),
                OrderTypeEnum.allowableValues(),
                BaseBusinessErrorCodeEnum.ENUM_PARAM_MUST_BE_IN_ALLOWABLE_VALUE,
                "orderTypes",
                OrderTypeEnum.allowableValues());

        // 校验 订单状态 传值是否正确
        ParamCheckUtil.checkIntSetAllowableValues(
                param.getOrderStatus(),
                OrderStatusEnum.allowableValues(),
                BaseBusinessErrorCodeEnum.ENUM_PARAM_MUST_BE_IN_ALLOWABLE_VALUE,
                "orderStatus",
                OrderStatusEnum.allowableValues());

        Integer maxSize = param.MAX_PAGE_SIZE;
        // 校验 查询的订单号数量 是否超过最大值
        checkSetMaxSize(param.getOrderIds(),maxSize,"orderIds");
        // 校验 查询的订单号数量 是否超过最大值
        checkSetMaxSize(param.getSellerIds(),maxSize,"sellerIds");

        checkSetMaxSize(param.getParentOrderIds(),maxSize,"parentOrderIds");
        checkSetMaxSize(param.getReceiverNames(),maxSize,"receiverNames");
        checkSetMaxSize(param.getReceiverPhones(),maxSize,"receiverPhones");
        checkSetMaxSize(param.getTradeNos(),maxSize,"tradeNos");
        checkSetMaxSize(param.getUserIds(),maxSize,"userIds");
        checkSetMaxSize(param.getSkuCodes(),maxSize,"skuCodes");
        checkSetMaxSize(param.getProductNames(),maxSize,"productNames");
    }

    /**
     * 校验参数size是否超过最大值限制
     * @author xuyou
     * @date: 2022/6/24 14:10
     */
    private void checkSetMaxSize(Set setParam, Integer maxSize, String paramName) {
        BaseBusinessErrorCodeEnum baseBusinessErrorCodeEnum = BaseBusinessErrorCodeEnum.COLLECTION_PARAM_CANNOT_BEYOND_MAX_SIZE;
        ParamCheckUtil.checkSetMaxSize(setParam, maxSize,
                baseBusinessErrorCodeEnum,paramName
                ,maxSize);
    }

}
